package com.linkgie.galaxyframework.utils.bean;

import java.beans.PropertyDescriptor;
import java.util.WeakHashMap;

import com.linkgie.galaxyframework.utils.StringConverter;

class BeanConverterRegistry {

    /**
     * Bean类型的转换器；
     * <p>
     * key 是Bean的类型；
     * <br>
     * value 是转换器的类型；
     */
    private static final WeakHashMap<Class<?>, Class<?>> BEAN_CONVERTER_TYPES = new WeakHashMap<>();

    /**
     * 数据转换器；
     * <p>
     * key 是转换器的类型；
     * <br>
     * value 是转换器的实例；
     */
    private static final WeakHashMap<Class<? extends StringConverter<?>>, StringConverter<?>> DATA_CONVERTERS = new WeakHashMap<>();

    /**
     * 返回属性的转换器；
     * <p>
     * 如果没有，则返回 null ；
     * 
     * @param propertyDescriptor
     * @return
     */
    @SuppressWarnings("rawtypes")
    static StringConverter getPropertyConverter(PropertyDescriptor propertyDescriptor) {
        BeanProperty beanPropertyAnno = null;
        // 优先根据属性上的标注 BeanProperty 来创建转换器；
        // get 方法声明优先，其次是 set 方法声明；
        // 如果方法未声明转换器，则根据属性类型上的标注 Bean 来创建转换器；
        if (propertyDescriptor.getReadMethod() != null) {
            beanPropertyAnno = propertyDescriptor.getReadMethod().getAnnotation(BeanProperty.class);
        }
        if (beanPropertyAnno == null) {
            if (propertyDescriptor.getWriteMethod() != null) {
                beanPropertyAnno = propertyDescriptor.getWriteMethod().getAnnotation(BeanProperty.class);
            }
        }
        if (beanPropertyAnno != null && beanPropertyAnno.converter() != null) {
            Class<?> converterClass = beanPropertyAnno.converter();
            return getDataConverter(converterClass);
        }

        // 根据属性类型上的标注 Bean 来创建转换器；
        return getBeanConverter(propertyDescriptor.getPropertyType());
    }

    /**
     * 返回 Bean 转换器；
     * <p>
     * 如果没有，则返回 null；
     * 
     * @param beanType
     * @return
     */
    static StringConverter<?> getBeanConverter(Class<?> beanType) {
        Class<?> conveterClass = BEAN_CONVERTER_TYPES.get(beanType);
        if (conveterClass != null) {
            return getDataConverter(conveterClass);
        }

        Bean beanAnno = beanType.getAnnotation(Bean.class);
        if (beanAnno == null) {
            // 设置为默认值；
            BEAN_CONVERTER_TYPES.put(beanType, Bean.NULL_CONVERTER);
            return null;
        }
        conveterClass = beanAnno.converter();
        StringConverter<?> converter = getDataConverter(conveterClass);
        if (converter == null) {
            BEAN_CONVERTER_TYPES.put(beanType, Bean.NULL_CONVERTER);
            return null;
        }
        BEAN_CONVERTER_TYPES.put(beanType, conveterClass);
        return converter;

    }

    @SuppressWarnings("unchecked")
    private static StringConverter<?> getDataConverter(Class<?> converterClass) {
        if (converterClass == null) {
            return null;
        }
        if (converterClass == Bean.NULL_CONVERTER) {
            return null;
        }
        if (!StringConverter.class.isAssignableFrom(converterClass)) {
            return null;
        }
        if (converterClass.isInterface()) {
            return null;
        }
        if (converterClass.isArray() || converterClass.isEnum()) {
            return null;
        }
        StringConverter<?> converter = DATA_CONVERTERS.get(converterClass);
        if (converter == null) {
            converter = (StringConverter<?>) org.springframework.beans.BeanUtils
                    .instantiateClass(converterClass);
            DATA_CONVERTERS.put((Class<? extends StringConverter<?>>) converterClass, converter);
        }
        return (StringConverter<?>) converter;
    }
}
